//Documentation complete
/**
 * @author Alex
 * @version 2009MR21
 */

package problemDomain;

import static problemDomain.ErrorBean.*;
import static problemDomain.ErrorBean.ErrorCode.*;
import static utilities.XMLTools.*;

import java.util.*;

/**
 * A food order in the system.
 */
public class OrderBean implements Bean {
	
	/* Constants */
	
	private static final long serialVersionUID = -433219782083038933L;
	
	/* END Constants */
	
	
	/* Attributes */
	
	private int id;
	private EmployeeAccountBean createdBy;
	private PatronAccountBean patron;
	private Calendar orderPlaced;
	private String orderStatus;
	private String paymentStatus;
	private List<OrderItemBean> orderItemList;
	private DeliveryBean delivery;
	
	/* tax */
	private double gstAmount;
	private double pstAmount;
	private double balancePaid;
	
	/* END Attributes */
	
	
	/* Constructors */
	
	/**
	 * Constructs an <code>OrderBean</code> with default values.
	 */
	public OrderBean () {
		id = 0;
		createdBy = null;
		orderPlaced = null;
		orderStatus = "";
		orderItemList = null;
		delivery = null;
		paymentStatus = "";
		patron = null;
		gstAmount = 0.0;
		pstAmount = 0.0;
		balancePaid = 0.0;
	}
	
	/**
	 * Constructs an <code>OrderBean</code> with an ID.
	 * @param id the ID number
	 */
	public OrderBean (int id) {
		this();
		this.id = id;
	}
	
	/**
	 * Constructs an <code>OrderBean</code> with specified values.
	 * @param id The ID number
	 * @param createdBy The account that created the order
	 * @param orderPlaced The date when the order is placed
	 * @param orderStatus The status of the order
	 * @param orderItemList The list of items in the order
	 * @param delivery The delivery information of the order
	 * @param paymentStatus The payment status of the order
	 * @param patron The patron that is placing the order
	 * @param gstAmount GST amount to be levied on the order
	 * @param pstAmount PST amount to be levied on the order
	 * @param balancePaid The balance paid on the order
	 */
	public OrderBean (int id, EmployeeAccountBean createdBy,
			Calendar orderPlaced, String orderStatus, List<OrderItemBean> orderItemList, DeliveryBean delivery,
			String paymentStatus, PatronAccountBean patron, double gstAmount, double pstAmount, double balancePaid) {
		this.gstAmount = gstAmount;
		this.pstAmount = pstAmount;
		this.createdBy = createdBy;
		this.delivery = delivery;
		this.id = id;
		this.orderItemList = orderItemList;
		this.orderPlaced = orderPlaced;
		this.orderStatus = orderStatus;
		this.paymentStatus = paymentStatus;
		this.patron = patron;
		this.balancePaid = balancePaid;
	}
	
	/* END Constructors */
	
	
	/* Accessors */
	
	/**
	 * Returns the ID number of the order.
	 * @return the ID number of the order
	 */
	public int getId () {
		return id;
	}

	/**
	 * Returns the date when the order is placed.
	 * @return the date when the order is placed
	 */
	public Calendar getOrderPlaced () {
		return orderPlaced;
	}

	/**
	 * Returns the status of the order.
	 * @return the status of the order
	 */
	public String getOrderStatus () {
		return orderStatus;
	}

	/**
	 * Returns the list of items in the order
	 * @return The list of items in the order
	 */
	public List<OrderItemBean> getOrderItemList () {
		return orderItemList;
	}

	/**
	 * Returns the delivery information of the order.
	 * @return The delivery information of the order
	 */
	public DeliveryBean getDelivery () {
		return delivery;
	}

	/**
	 * Returns the payment status of the order.
	 * @return the payment status of the order
	 */
	public String getPaymentStatus () {
		return paymentStatus;
	}

	/**
	 * Returns the gstAmount rate to be levied on the order.
	 * @return the gstAmount rate to be levied on the order
	 */
	public double getGstAmount () {
		return gstAmount;
	}

	/**
	 * Returns the pstAmount rate to be levied on the order.
	 * @return the pstAmount rate to be levied on the order
	 */
	public double getPstAmount () {
		return pstAmount;
	}

	/**
	 * Returns the balancePaid on the order.
	 * @return the balancePaid on the order
	 */
	public double getBalancePaid () {
		return balancePaid;
	}

	/**
	 * Returns the employee account that created the order.
	 * @return the employee account that created the order
	 */
	public EmployeeAccountBean getCreatedBy () {
		return createdBy;
	}
	
	/**
	 * Returns the first name of the unregistered patron who created the order. 
	 * Returns null if the patron is registered and the order is created online.
	 * @return the patronFirstName
	 */
	public PatronAccountBean getPatron () {
		return patron;
	}
	
	/* END Accessors */
	
	
	/* Mutators */
	
	/**
	 * Sets the ID number of the order.
	 * @param id the ID number of the order to set
	 */
	public void setId (int id) {
		this.id = id;
	}
	
	/**
	 * Sets the date when the order is placed.
	 * @param orderPlaced the date when the order is placed
	 */
	public void setOrderPlaced (Calendar orderPlaced) {
		this.orderPlaced = orderPlaced;
	}
	
	/**
	 * Sets the status of the order.
	 * @param orderStatus the status of the order to set
	 */
	public void setOrderStatus (String orderStatus) {
		this.orderStatus = orderStatus;
	}
	
	/**
	 * Sets the list of items in the order.
	 * @param orderItemList the list of items in the order to set
	 */
	public void setOrderItemList (List<OrderItemBean> orderItemList) {
		this.orderItemList = orderItemList;
	}
	
	/**
	 * Sets the delivery information of the order.
	 * @param delivery the delivery information of the order to set
	 */
	public void setDelivery (DeliveryBean delivery) {
		this.delivery = delivery;
	}
	
	/**
	 * Sets the payment information of the order.
	 * @param paymentStatus the payment information of the order to set
	 */
	public void setPaymentStatus (String paymentStatus) {
		this.paymentStatus = paymentStatus;
	}
	
	/**
	 * Sets the gstAmount rate to be levied on the order.
	 * @param gst the gstAmount rate to be levied on the order to set
	 */
	public void setGstAmount (double gst) {
		gstAmount = gst;
	}
	
	/**
	 * Sets the pstAmount rate to be levied on the order.
	 * @param pst the pstAmount rate to be levied on the order to set
	 */
	public void setPstAmount (double pst) {
		pstAmount = pst;
	}
	
	/**
	 * Sets the balancePaid on the order.
	 * @param balancePaid the balancePaid on the order to set
	 */
	public void setBalancePaid (double balancePaid) {
		this.balancePaid = balancePaid;
	}
	
	/**
	 * Sets the employee account that created the order.
	 * @param createdBy the <code>EmployeeAccountBean</code> that created the order to set
	 */
	public void setCreatedBy (EmployeeAccountBean createdBy) {
		this.createdBy = createdBy;
	}

	/**
	 * Sets the patron account that this order is for.
	 * @param patron the <code>PatronAccountBean</code> that this order is for
	 */
	public void setPatron (PatronAccountBean patron) {
		this.patron = patron;
	}
	
	/**
	 * Adds an order item to the list of the items in this order.
	 * @param oib The order item to be added to this order 
	 */
	public void addOrderItem(OrderItemBean oib) {
		createOrderItemList().add(oib);
	}
	
	/* END Mutators */
	
	
	/* Methods */
	
	/**
	 * Returns the sub total amount of this Order.
	 * @return the sub total amount of this Order
	 */
	public double getSubtotal () {
		double subtotal = 0.0;
		if (orderItemList != null)
			for (int i = 0; i < orderItemList.size(); i++) {
				OrderItemBean oid = orderItemList.get(i);
				subtotal += oid.getTotal();
			}
		return subtotal;
	}
	
	/**
	 * Returns the amount of tax of this order.
	 * @return the amount of tax of this order
	 */
	public double getTotalTax() {
		return Math.round(100.0 * getSubtotal() * (gstAmount + pstAmount)) / 100.0;
	}
	
	/**
	 * Returns the total price of this Order.
	 * @return the total price of this Order
	 */
	public double getTotal () {
		return getSubtotal() + getTotalTax();
	}
	
	/* END Methods */
	
	
	/* Local Methods */
	
	private List<OrderItemBean> createOrderItemList () {
		if (orderItemList == null)
			orderItemList = new ArrayList<OrderItemBean>();
		return orderItemList;
	}
	
	/* END Local Methods */
	
	
	/* (Bean) Methods */
	
	@Override
	public boolean isValid () throws ErrorBean {
		if (id < 0)
			throwError(
				ORDER_ID_INVALID,
				String.valueOf(id),
				this);
		
		if (createdBy != null)
			createdBy.isValid();
		
		if (patron != null)
			patron.isValid();
		
		if (orderPlaced != null && orderPlaced.compareTo(Calendar.getInstance()) > 0)
			throwError(
				ORDER_DATEPLACED_INVALID,
				String.valueOf(orderPlaced),
				this);
		
		if ("".equals(orderStatus) || orderStatus == null)
			throwError(
				ORDER_STATUS_INVALID,
				orderStatus,
				this);
		
		if ("".equals(paymentStatus) || paymentStatus == null)
			throwError(
				ORDER_PAYMENTSTATUS_INVALID,
				paymentStatus,
				this);
		
		if (orderItemList != null) {
			Iterator<OrderItemBean> i = orderItemList.iterator();
			while (i.hasNext())
				i.next().isValid();
		}
		
		if (delivery != null)
			delivery.isValid();
		
		return true;
	}
	
	@Override
	public String toXML () {
		StringBuilder sb = new StringBuilder();
		sb.append("<order>");
		sb.append("<id>" + id + "</id>");
		sb.append("<createdby>" + (createdBy != null ? createdBy.toXML() : "") + "</createdby>");
		sb.append("<placed>");
		sb.append("<day>" + (orderPlaced != null ? orderPlaced.get(Calendar.DAY_OF_MONTH): "") + "</day>");
		sb.append("<month>" + (orderPlaced != null ? orderPlaced.get(Calendar.MONTH): "") + "</month>");
		sb.append("<year>" + (orderPlaced != null ? orderPlaced.get(Calendar.YEAR): "") + "</year>");
		sb.append("<hour>"  + (orderPlaced != null ? orderPlaced.get(Calendar.HOUR_OF_DAY): "") + "</hour>");
		sb.append("<minute>"  + (orderPlaced != null ? orderPlaced.get(Calendar.MINUTE): "") + "</minute>");
		sb.append("</placed>");
		sb.append("<status>" + orderStatus + "</status>");
		sb.append(encapsulateBeanListXML(orderItemList, "itemlist"));
		if (delivery != null)
			sb.append(delivery.toXML());
		else
			sb.append("<delivery></delivery>");
		sb.append("<paymentstatus>" + paymentStatus + "</paymentstatus>");
		if (patron != null)
			sb.append(patron.toXML());
		else
			sb.append("<patron></patron>");
		sb.append("<subtotal>" + getSubtotal() +"</subtotal>");
		sb.append("<tax>" + getTotalTax() +"</tax>");
		sb.append("<order-total>" + getTotal() +"</order-total>");
		sb.append("<gst>" + gstAmount + "</gst>");
		sb.append("<pst>" + pstAmount + "</pst>");
		sb.append("<balancepaid>" + balancePaid + "</balancepaid>");
		sb.append("</order>");
		return encodeEntities(sb.toString());
	}
	
	/* END (Bean) Methods */
	
	
	/* (Object) Methods */
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("ID: " + id + '\n');
		sb.append("Created by : " + createdBy + '\n');
		//todo
		sb.append("Order Placed: " + orderPlaced + '\n');
		sb.append("Order Status: " + orderStatus + '\n');
		sb.append("Item List:\n");
		if (orderItemList != null) {
			Iterator<OrderItemBean> i = orderItemList.iterator();
			while (i.hasNext())
				sb.append(i.next().toString().replaceAll("^(.*)$", "\t$1") + '\n');
		} else {
			sb.append("\tItem list is null.\n");
		}
		sb.append("Delivery:\n");
		if (patron != null)
			sb.append(delivery.toString().replaceAll("^(.*)$", "\t$1") + '\n');
		else
			sb.append("\tnull\n");
		sb.append("Payment Status: " + paymentStatus + '\n');
		sb.append("Patron:\n");
		if (patron != null)
			sb.append(patron.toString().replaceAll("^(.*)$", "\t$1") + '\n');
		else
			sb.append("\tnull\n");
		sb.append("GST Amount: " + gstAmount + '\n');
		sb.append("PST Amount: " + pstAmount + '\n');
		sb.append("Balance Paid: " + balancePaid + "\n\n");
		return sb.toString();
	}
	
	/* END (Object) Methods */
	
}
